package com.fxu.gen;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.fxu.framework.biz.rest.ApiBizRest;
import com.fxu.framework.core.base.Constant;
import com.fxu.framework.core.base.Result;
import com.fxu.gen.enums.SignEnum;
import com.fxu.gen.enums.TplEnum;
import com.fxu.tpl.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * 模板生成基础类
 * @author fangxu
 * @version 1.0.0
 */
public abstract class Base implements Auto {
	protected final static Logger logger = LoggerFactory.getLogger(Base.class);
	protected final static String corePackage = Result.class.getPackage().getName().substring(0,
			Result.class.getPackage().getName().lastIndexOf("."));

	protected boolean destFileExist = false;
	protected List<String> imports = new ArrayList<>();

	protected String tplProject = "fxu";
	protected String tplClass = "";
	protected String tplPackage = "";
	protected String thisPackage = "";
	protected String destProject = "";
	protected String tplModule;
	protected String thisModule;
	protected String fileTxt;
	protected String tableBean;
	protected String priKeyCln;

	protected Table table;
	protected Module module;
	protected TplEnum tplEnum;
	protected Project project;
	protected List<Column> columns;
	protected List<Index> indexs;
	protected List<Link> links;
	
	public Base(Table table, TplEnum tplEnum, File destFile) {
		super();
		this.table = table;
		this.tplEnum = tplEnum;
		this.project = table.getProject();
		this.module = table.getModule();
		this.links = table.getLinkList() == null ? new ArrayList<>() : table.getLinkList();
		this.indexs = table.getIndexList();
		this.columns = table.getColumnList();
		this.priKeyCln = getPriKeyClnName(columns);

		if (module != null) {
			thisModule = module.getName().replace("/", ".");
		}

		if (project != null) {
			this.tplClass = project.getTplClass();
			this.destProject = project.getDstProject();
			this.tplModule = project.getTplModule();
			this.fileTxt = this.tplPackage = "";

			this.destFileExist = destFile != null && destFile.exists();
			if (destFileExist && tplEnum != TplEnum.SQL) {
				this.fileTxt = FileUtil.readUtf8String(destFile);
			} else if (tplEnum != TplEnum.SQL) {
				this.fileTxt = FileUtil.readString(getTplUrl(tplEnum), Charset.defaultCharset());
			}
			this.tplPackage = getPackage(fileTxt);
			this.thisPackage = tplPackage.replace("." + project.getTplProject() + "." + tplModule + ".",
					"." + destProject + "." + thisModule + ".");
		}

		tableBean = AutoUtil.getBean(table.getName());
	}
	
	// 获取模板文件
	public URL getTplUrl(TplEnum tplEnum) {
		if (tplEnum == TplEnum.VueHtml) {
			// return new File(project.getVueTpl());
			return Base.class.getClassLoader().getResource("tpl/index.vue");
		} else if (tplEnum == TplEnum.VbenAdmin) {
			return Base.class.getClassLoader().getResource("tpl/vbenAdmin.vue");
		} else if (tplEnum == TplEnum.VbenVue3) {
			return Base.class.getClassLoader().getResource("tpl/vbenVue3.vue");
		} else {
			String tplClassName = tplEnum.getName(tplClass);
			return Base.class.getClassLoader().getResource("tpl/" + tplClassName);
			// return new File(ResourceUtil.getResource("tpl/" + tplClassName).getFile());
			// || file.getName().equals(tplClassName.replace("ServiceImplTest", "Test")
			// List<File> list = FileUtil.loopFiles(getTplPath(tplEnum), file -> file.getName().equals(tplClassName));
			// return list != null && list.size() > 0 ? list.get(0) : null;
		}
	}

	// 获取模版文件位置
	private String getTplPath(TplEnum tplEnum) {
		switch (tplEnum) {
		case Entity:
		case Enums:
		case Feign:
		case FeignFallback:
		case Service:
			return project.getTplPath() + project.getTplFacade();
		
		case RestImpl:
		case RestService:
		case RestServiceImpl:
		case Controller:
			return project.getTplPath() + project.getTplRest();
			
		case ServiceImpl:
		case Mapper:
		case MapperXml:
			return project.getTplPath() + project.getTplService();
		
		default:
			break;
		}
		return null;
	}

	@Override
	public String doReplace() {
		String fileTxt = this.fileTxt;
		if (!destFileExist) {
			fileTxt = replaceMove(fileTxt); //去掉代码
			fileTxt = replaceClass(fileTxt); //修改类名
			fileTxt = replaceComment(fileTxt); //修改注释
			fileTxt = replaceImports(fileTxt, true); //放最后才能收集imports
		}
		return fileTxt;
	}
	
	//替换类名[小写大写开头都替换]
	protected String replaceClass(final String txt) {
		String newTxt = txt;
		String bizPackage = ApiBizRest.class.getPackage().getName().substring(0, ApiBizRest.class.getPackage().getName().lastIndexOf("."));
		newTxt = newTxt.replace(bizPackage, "{{BIZ_PACKAGE}}");
		newTxt = newTxt.replace(corePackage, "{{CORE_PACKAGE}}");
		newTxt = newTxt.replace("." + project.getTplProject() + ".core.", "{{CORE_PROJECT_MODULE}}");
		newTxt = newTxt.replace("org.springframework.cloud", "{{SPRING_FW_CLOUD}}");
		newTxt = newTxt.replace("spring-cloud", "{{SPRING_CLOUD}}");
		
		newTxt = newTxt.replace("/remote/" + StrUtil.lowerFirst(tplClass), "{{REMOTE-URL}}");
		newTxt = newTxt.replace("\""+tplModule+"-service\"", "{{SERVICE-URL}}");
		newTxt = newTxt.replace("." + tplModule, "{{MODULE}}"); // + "."
		newTxt = newTxt.replace("." + project.getTplProject(), "{{PROJECT}}"); // + "."
		newTxt = newTxt.replace(tplClass, tableBean);
		newTxt = newTxt.replace(StrUtil.lowerFirst(tplClass), StrUtil.lowerFirst(tableBean));
		newTxt = newTxt.replace("{{REMOTE-URL}}", "/remote/" + StrUtil.lowerFirst(tableBean));
		newTxt = newTxt.replace("{{SERVICE-URL}}", "\"" + thisModule + "-service\"");
		newTxt = newTxt.replace("{{MODULE}}", "." + thisModule);
		newTxt = newTxt.replace("{{PROJECT}}", "." + destProject);

		newTxt = newTxt.replace("{{CORE_PROJECT_MODULE}}", "."+project.getTplProject()+".core.");
		newTxt = newTxt.replace("{{SPRING_FW_CLOUD}}", "org.springframework.cloud");
		newTxt = newTxt.replace("{{SPRING_CLOUD}}", "spring-cloud");
		newTxt = newTxt.replace("{{CORE_PACKAGE}}", corePackage);
		newTxt = newTxt.replace("{{BIZ_PACKAGE}}", bizPackage);
		return newTxt;
	}
	
	/** 测试代码去掉 */
	protected String replaceMove(final String txt) {
		return replace(txt, SignEnum.ClassMove, new StringBuffer());
	}
	
	/**
	 * 替换引入包列表
	 * @param txt 文件内容
	 * @param isClean true: 替换，false: 增加
	 * @return 替换后内容
	 */
	protected String replaceImports(final String txt, boolean isClean) {
		StringBuffer buffer = new StringBuffer();
		String newTxt = txt;
		for (String im : imports) {
			if (!newTxt.contains("import " + im)) {
				buffer.append("import ").append(im).append(";\n");
			}
		}
		if (isClean) {
			newTxt = replace(newTxt, SignEnum.ClassImport, buffer);
		} else if (buffer.length() > 0) {
			newTxt = newTxt.replace(SignEnum.ClassComment.getStartKey(), buffer + "\n" + SignEnum.ClassComment.getStartKey());
			//newTxt = replace(newTxt, ReplaceEnum.ClassImport, buffer);
		}
		return newTxt;
	}
	/**
	 * 替换注释
	 * @param txt 替换的内容
	 * @return 替换后内容
	 */
	protected String replaceComment(final String txt) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(" * <p>").append(project.getCompany()).append("</p>\r\n");
		buffer.append(" * ").append(table.getCmmt()).append("表：[").append(table.getName()).append("]的").append(tplEnum.getCmmt()).append("\r\n");
		buffer.append(" * @author ").append(project.getAuthor()).append("\r\n");
		buffer.append(" * @since ").append(DateUtil.today()).append("\r\n");
		return replace(txt, SignEnum.ClassComment, buffer);
	}

	protected static String replace(final String txt, SignEnum re, StringBuffer value) {
		String newTxt = txt;
		String startKey = re.getStartKey();
		String endKey = re.getEndKey();
		int start = txt.indexOf(startKey);
		int end = txt.indexOf(endKey);
		if (start > -1 && end > -1 && start < end) {
			newTxt = newTxt.replace(newTxt.substring(start, end), startKey + "\r\n" + value);
			if (re == SignEnum.ClassMove || re == SignEnum.MapperXmlMove || re == SignEnum.ClassImport
					|| re == SignEnum.PageReqColumn || re == SignEnum.Controller) {
				newTxt = newTxt.replace(startKey + "\r\n", "");
				newTxt = newTxt.replace(startKey + "\n", "");
				newTxt = newTxt.replace(endKey, ""); // 留个换行
			}
		} else {
			if (re != SignEnum.ClassMove && re != SignEnum.MapperXmlMove) {
				logger.info(String.format("找不到关键词{%s}=>{%d},{%s}=>{%d}", startKey, start, endKey, end));
			}
		}
		return newTxt;
	}

	public String getTablePackage(Table table) {
		String tblModule = table.getModule().getName().replace("/", ".");
		//替换时候错误的包名
		String tmp = tplPackage.replace("." + project.getTplProject() + ".", "." + destProject + ".");
		if (destFileExist) {
			return tmp.replace("." + thisModule + ".", "." + tblModule + ".");
		} else {
			return tmp.replace("." + tplModule + ".", "." + tblModule + ".");
		}
	}

	public String getLinkPropName(Link link) {
		return getLinkPropName(link, false);
	}

	public String getLinkPropName(Link link, boolean all) {
		String module = link.getLinkTable().getModule().getName();
		String name = link.getLinkTable().getName();
		if (!all) {
			name = name.contains("_") ? name.substring(name.lastIndexOf("_") + 1) : name;
		}
		name = AutoUtil.firstLowerBean(name);
		if (name.startsWith(module)) {
			return StrUtil.lowerFirst(name.substring(module.length()));
		}
		return name;
	}
	
	public String getPackage(String fileTxt) {
		int start = fileTxt.indexOf("package ");
		int end = fileTxt.indexOf(";");
		if (start > -1 && end > start) {
			return fileTxt.substring(start + "package ".length(), end);
		}
		return "";
	}

	public static boolean isTrue(Boolean bool) {
		return bool != null && bool;
	}

	// 返回唯一关键字段
	public static Column getPriKeyColumn(List<Column> columns) {
		return CollUtil.findOne(columns, v -> Constant.ID_NAME.equals(v.getName()) || v.getCmmt().equals("自增ID") || v.getCmmt().equals("UUID"));
	}

	public static String getPriKeyClnName(List<Column> columns) {
		Column cln = getPriKeyColumn(columns);
		return cln == null ? Constant.ID_NAME : cln.getName();
	}
}
